package com.soma.game.service.impl;

import com.google.common.base.Preconditions;
import com.soma.game.enums.BooleanStatus;
import com.soma.game.service.BaseService;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;

/**
 * 异常处理需要细化，如NoSuchMethodException等需要特殊处理，不能把业务异常也一起拦截
 *
 * @author: ivan.enjoy<haif.enjoy@gmail.com>
 * @date: 17/6/28.
 */
@Service
public abstract class BaseServiceImpl<Mapper, Record, Example> implements BaseService<Record, Example> {

    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    public Mapper mapper;

    @Override
    public Long countByExample(Example example) {
        try {
            Method countByExample = mapper.getClass().getDeclaredMethod("countByExample", example.getClass());
            Object result = countByExample.invoke(mapper, example);
            return Long.parseLong(String.valueOf(result));
        } catch (ReflectiveOperationException e) {
            logger.error("countByExample error,{}", ExceptionUtils.getMessage(e));
            if(e instanceof InvocationTargetException) {
                throw new RuntimeException("SQL错误:"+((InvocationTargetException) e).getTargetException().getMessage());
            }
            throw new RuntimeException("SQL错误:"+e.getMessage());
        }
    }

    @Override
    public Long deleteByExample(Example example) {
        try {
            Method deleteByExample = mapper.getClass().getDeclaredMethod("deleteByExample", example.getClass());
            Object result = deleteByExample.invoke(mapper, example);
            return Long.parseLong(String.valueOf(result));
        } catch (ReflectiveOperationException e) {
            logger.error("deleteByExample error,{}", ExceptionUtils.getMessage(e));
            if(e instanceof InvocationTargetException) {
                throw new RuntimeException("SQL错误:"+((InvocationTargetException) e).getTargetException().getMessage());
            }
            throw new RuntimeException("SQL错误:"+e.getMessage());
        }
    }

    @Override
    public Long deleteByPrimaryKey(Long id) {
        try {
            Method deleteByPrimaryKey = mapper.getClass().getDeclaredMethod("deleteByPrimaryKey", id.getClass());
            Object result = deleteByPrimaryKey.invoke(mapper, id);
            return Long.parseLong(String.valueOf(result));
        } catch (ReflectiveOperationException e) {
            logger.error("deleteByPrimaryKey error,{}", ExceptionUtils.getMessage(e));
            if(e instanceof InvocationTargetException) {
                throw new RuntimeException("SQL错误:"+((InvocationTargetException) e).getTargetException().getMessage());
            }
            throw new RuntimeException("SQL错误:"+e.getMessage());
        }
    }

    @Override
    public Long insert(Record record) {
        try {
            Method insert = mapper.getClass().getDeclaredMethod("insert", record.getClass());
            Object result = insert.invoke(mapper, record);
            return Long.parseLong(String.valueOf(result));
        } catch (ReflectiveOperationException e) {
            logger.error("insert error,{}", ExceptionUtils.getMessage(e));
            if(e instanceof InvocationTargetException) {
                throw new RuntimeException("SQL错误:"+((InvocationTargetException) e).getTargetException().getMessage());
            }
            throw new RuntimeException("SQL错误:"+e.getMessage());
        }
    }

    @Override
    public Long insertSelective(Record record) {
        try {
            Method insertSelective = mapper.getClass().getDeclaredMethod("insertSelective", record.getClass());
            Object result = insertSelective.invoke(mapper, record);
            return Long.parseLong(String.valueOf(result));
        } catch (ReflectiveOperationException e) {
            logger.error("insertSelective error,{}", ExceptionUtils.getMessage(e));
            if(e instanceof InvocationTargetException) {
                throw new RuntimeException("SQL错误:"+((InvocationTargetException) e).getTargetException().getMessage());
            }
            throw new RuntimeException("SQL错误:"+e.getMessage());
        }
    }


    @Override
    public List<Record> selectByExample(Example example) {
        try {
            Method selectByExample = mapper.getClass().getDeclaredMethod("selectByExample", example.getClass());
            Object result = selectByExample.invoke(mapper, example);
            return (List<Record>) result;
        } catch (ReflectiveOperationException e) {
            logger.error("selectByExample error,{}", ExceptionUtils.getMessage(e));
            if(e instanceof InvocationTargetException) {
                throw new RuntimeException("SQL错误:"+((InvocationTargetException) e).getTargetException().getMessage());
            }
            throw new RuntimeException("SQL错误:"+e.getMessage());
        }
    }


    @Override
    public Record selectByPrimaryKey(Long id) {
        try {
            Method selectByPrimaryKey = mapper.getClass().getDeclaredMethod("selectByPrimaryKey", id.getClass());
            Object result = selectByPrimaryKey.invoke(mapper, id);
            return (Record) result;
        } catch (ReflectiveOperationException e) {
            logger.error("selectByPrimaryKey error,{}", ExceptionUtils.getMessage(e));
            if(e instanceof InvocationTargetException) {
                throw new RuntimeException("SQL错误:"+((InvocationTargetException) e).getTargetException().getMessage());
            }
            throw new RuntimeException("SQL错误:"+e.getMessage());
        }
    }

    @Override
    public Long updateByExampleSelective(Record record, Example example) {
        try {
            Method updateByExampleSelective = mapper.getClass().getDeclaredMethod("updateByExampleSelective", record.getClass(), example.getClass());
            Object result = updateByExampleSelective.invoke(mapper, record, example);
            return Long.parseLong(String.valueOf(result));
        } catch (ReflectiveOperationException e) {
            logger.error("updateByExampleSelective error,{}", ExceptionUtils.getMessage(e));
            if(e instanceof InvocationTargetException) {
                throw new RuntimeException("SQL错误:"+((InvocationTargetException) e).getTargetException().getMessage());
            }
            throw new RuntimeException("SQL错误:"+e.getMessage());
        }
    }

    @Override
    public Long updateByExample(Record record, Example example) {
        try {
            Method updateByExample = mapper.getClass().getDeclaredMethod("updateByExample", record.getClass(), example.getClass());
            Object result = updateByExample.invoke(mapper, record, example);
            return Long.parseLong(String.valueOf(result));
        } catch (ReflectiveOperationException e) {
            logger.error("updateByExample error,{}", ExceptionUtils.getMessage(e));
            if(e instanceof InvocationTargetException) {
                throw new RuntimeException("SQL错误:"+((InvocationTargetException) e).getTargetException().getMessage());
            }
            throw new RuntimeException("SQL错误:"+e.getMessage());
        }
    }


    @Override
    public Long updateByPrimaryKeySelective(Record record) {
        try {
            Method updateByPrimaryKeySelective = mapper.getClass().getDeclaredMethod("updateByPrimaryKeySelective", record.getClass());
            Object result = updateByPrimaryKeySelective.invoke(mapper, record);
            return Long.parseLong(String.valueOf(result));
        } catch (ReflectiveOperationException e) {
            logger.error("updateByPrimaryKeySelective error,{}", ExceptionUtils.getMessage(e));
            if(e instanceof InvocationTargetException) {
                throw new RuntimeException("SQL错误:"+((InvocationTargetException) e).getTargetException().getMessage());
            }
            throw new RuntimeException("SQL错误:"+e.getMessage());
        }
    }


    @Override
    public Long updateByPrimaryKey(Record record) {
        try {
            Method updateByPrimaryKey = mapper.getClass().getDeclaredMethod("updateByPrimaryKey", record.getClass());
            Object result = updateByPrimaryKey.invoke(mapper, record);
            return Long.parseLong(String.valueOf(result));
        } catch (ReflectiveOperationException e) {
            logger.error("updateByPrimaryKey error,{}", ExceptionUtils.getMessage(e));
            if(e instanceof InvocationTargetException) {
                throw new RuntimeException("SQL错误:"+((InvocationTargetException) e).getTargetException().getMessage());
            }
            throw new RuntimeException("SQL错误:"+e.getMessage());
        }
    }

    @Override
    public Record load(Long id) {
        Preconditions.checkNotNull(id, "id不能为空");
        return selectByPrimaryKey(id);
    }

    @Override
    public Record loadActive(Long id) {
        Record record = load(id);
        if (record != null) {
            try {
                Method getActiveFlg = record.getClass().getDeclaredMethod("getActiveFlg");
                BooleanStatus booleanStatus = (BooleanStatus) getActiveFlg.invoke(record);
                if (booleanStatus == BooleanStatus.Y) {
                    return record;
                }
            } catch (ReflectiveOperationException e) {
                logger.error("loadActive error,{}", ExceptionUtils.getMessage(e));
                if(e instanceof InvocationTargetException) {
                    throw new RuntimeException("SQL错误:"+((InvocationTargetException) e).getTargetException().getMessage());
                }
                throw new RuntimeException("SQL错误:"+e.getMessage());
            }
        }
        return null;
    }

    @Override
    public void inActive(Long id) {
        Record record = load(id);
        if (record != null) {
            try {
                Method setActiveFlg = record.getClass().getDeclaredMethod("setActiveFlg", BooleanStatus.class);
                setActiveFlg.invoke(record, BooleanStatus.N);
                updateByPrimaryKeySelective(record);
            } catch (ReflectiveOperationException e) {
                logger.error("inActive error,{}", ExceptionUtils.getMessage(e));
                if(e instanceof InvocationTargetException) {
                    throw new RuntimeException("SQL错误:"+((InvocationTargetException) e).getTargetException().getMessage());
                }
                throw new RuntimeException("SQL错误:"+e.getMessage());
            }
        }
    }

    @Override
    public Long save(Record record) {
        if (record != null) {
            try {
                Method getId = record.getClass().getDeclaredMethod("getId");
                try {
                    Method getCreatedDt = record.getClass().getDeclaredMethod("getCreatedDt");
                    Date createdDt = (Date) getCreatedDt.invoke(record);
                    if (createdDt == null) {
                        Method setCreatedDt = record.getClass().getDeclaredMethod("setCreatedDt", Date.class);
                        setCreatedDt.invoke(record, new Date());
                    }
                    Method setLastUpDt = record.getClass().getDeclaredMethod("setLastUpDt", Date.class);
                    setLastUpDt.invoke(record, new Date());
                    Long userId = 1l;
                    MethodUtils.invokeMethod(record, "setCreatedBy", userId);
                    MethodUtils.invokeMethod(record, "setLastUpBy", userId);
                } catch (ReflectiveOperationException e) {
                    //ignore
                }
                Object id = getId.invoke(record);
                if (id == null) {
                    id = insertSelective(record);
                } else {
                    id = updateByPrimaryKeySelective(record);
                }
                return Long.parseLong(String.valueOf(id));
            } catch (ReflectiveOperationException e) {
                logger.error("save error,{}", ExceptionUtils.getMessage(e));
                if(e instanceof InvocationTargetException) {
                    throw new RuntimeException("SQL错误:"+((InvocationTargetException) e).getTargetException().getMessage());
                }
                throw new RuntimeException("SQL错误:"+e.getMessage());
            }
        }

        return null;
    }

}
